﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace NeuralNetwork.Neurons
{
    public class SpikingNeuron : Neuron
    {
        private double threshold = 0;
        private int fired = 0;
        private int ready = 0;

        public SpikingNeuron(Network network) : base(network)
        {
            threshold = network.ActivationThreshold;
        }

        public long Fired
        {
            get { return fired; }
        }

        public long Ready
        {
            get { return ready; }
        }

        override public void Absorb(double charge)
        {
            if (ready <= 0) potential += charge;
        }

        override public void Reset()
        {
            Potential = 0;
            error = 0;
        }

        override public bool Update()
        {
            bool rc = false;

            // Increase time since last firing
            fired++;

            // Is the neuron resting?            
            if (ready > 0)            
            {
                ready--;
                return rc;
            }

            // Determine output
            double output = network.activation.Call(potential);

            // Check if potential exceeds firing threshold
            if (potential > threshold) 
            {
                // Charge all neighbouring neurons
                foreach (Axon axon in axons) axon.Absorb(potential);

                // Firing resets the potential of the neuron
                fired = 0;
                ready = network.NeuronRestTime;                
                potential = 0;
                rc = true;
            }

            return rc;
        }

        override public XmlNode Save(XmlDocument doc, XmlNode parent)
        {
            XmlNode node = base.Save(doc, parent);
            network.AddChildToNode(doc, node, "threshold", threshold);

            return node;
        }

        override public void Load(XmlNode neuronNode)
        {            
            // Get Layer data 
            foreach (XmlNode n in neuronNode.ChildNodes)
            {
                switch (n.Name.ToUpper())
                {
                    case "THRESHOLD":
                        threshold = Convert.ToDouble(n.InnerText.Trim());
                        break;

                    default:
                        //ignore
                        break;
                }
            }

            base.Load(neuronNode);
        }

    }
}
